﻿using System.Text;
using Admin.ApplicationLib.Entities;
using Admin.ApplicationLib.Repositories;
using Admin.ApplicationLib.Specifications;
using Admin.CommonLib.Models.Permission;
using AutoMapper;
using Swimj.CommonLib.Base;
using Swimj.Core.Providers;
using Swimj.Core.Securities;

namespace Admin.ApplicationLib.Services
{
    public class PermissionService : IPermissionService
    {
        private readonly IPermissionRepository _permissionRepository;
        private readonly IRoleRepository _roleRepository;
        private readonly ISecurityUser _securityUser;
        private readonly IMapper _mapper;
        private readonly IDateTimeProvider _dateTimeProvider;
        private readonly IExcelProvider _excelProvider;

        public PermissionService(IPermissionRepository permissionRepository,
            IRoleRepository roleRepository,
            ISecurityUser securityUser,
            IMapper mapper, IDateTimeProvider dateTimeProvider, IExcelProvider excelProvider)
        {
            _permissionRepository = permissionRepository;
            _roleRepository = roleRepository;
            _securityUser = securityUser;
            _mapper = mapper;
            _dateTimeProvider = dateTimeProvider;
            _excelProvider = excelProvider;
        }

        public async Task<PaginatedResult<PermissionInfoResponseDto>> QueryPermissionsByPageAsync(
            PermissionSearchRequestDto model)
        {
            var tuple = await _permissionRepository.QueryByPageAsync(model);
            return await PaginatedResult<PermissionInfoResponseDto>.SuccessAsync(
                _mapper.Map<List<PermissionInfoResponseDto>>(tuple.Item1),
                tuple.Item2, model.Page, model.Limit);
        }

        public async Task<Result<PermissionInfoResponseDto>> GetPermissionAsync(Guid id)
        {
            var permissionEntity = await _permissionRepository.GetByIdAsync(id);

            return await Result<PermissionInfoResponseDto>.SuccessAsync(
                _mapper.Map<PermissionInfoResponseDto>(permissionEntity));
        }

        public async Task<Result<PermissionInfoResponseDto>> CreatePermissionAsync(PermissionEditRequestDto model)
        {
            var permissionEntity = _mapper.Map<PermissionEntity>(model);

            // 设置权限的层级
            if (model.ParentId == null || model.ParentId == Guid.Empty)
            {
                permissionEntity.ParentId = null;
                permissionEntity.Level = 0;
            }
            else
            {
                var parentPermission = await _permissionRepository.GetByIdAsync(model.ParentId.Value);
                if (parentPermission != null) permissionEntity.Level = parentPermission.Level + 1;
            }

            permissionEntity = await _permissionRepository.AddAsync(permissionEntity);
            return await Result<PermissionInfoResponseDto>.SuccessAsync(
                _mapper.Map<PermissionInfoResponseDto>(permissionEntity));
        }

        public async Task<Result<PermissionInfoResponseDto>> UpdatePermissionAsync(Guid id,
            PermissionEditRequestDto model)
        {
            var permissionEntity = await _permissionRepository.GetByIdAsync(id);
            if (permissionEntity == null)
            {
                throw new Exception();
            }

            _mapper.Map(model, permissionEntity);

            // 设置权限的层级
            if (model.ParentId == null)
            {
                permissionEntity.Level = 0;
            }
            else
            {
                var parentPermission = await _permissionRepository.GetByIdAsync(model.ParentId.Value);
                if (parentPermission != null) permissionEntity.Level = parentPermission.Level + 1;
            }

            await _permissionRepository.UpdateAsync(permissionEntity);

            return await Result<PermissionInfoResponseDto>.SuccessAsync(
                _mapper.Map<PermissionInfoResponseDto>(permissionEntity));
        }

        public async Task<Result<PermissionInfoResponseDto>> DeletePermissionAsync(Guid id)
        {
            var permissionEntity = await _permissionRepository.GetByIdAsync(id);
            if (permissionEntity == null)
            {
                throw new Exception("");
            }

            await _permissionRepository.DeleteAsync(permissionEntity);

            return await Result<PermissionInfoResponseDto>.SuccessAsync(
                _mapper.Map<PermissionInfoResponseDto>(permissionEntity));
        }

        public async Task<Result<IList<PermissionTreeResponseDto>>> QueryPermissionsByTreeAsync(int treeType)
        {
            var permissionEntities =
                await _permissionRepository.ListAsync(new PermissionSpecification(new PermissionSearchRequestDto()
                {
                    TreeType = treeType
                }));
            IList<PermissionTreeResponseDto> treeDtos = new List<PermissionTreeResponseDto>();
            // 获取菜单目录
            var rootMenus = permissionEntities.Where(i => i.ParentId == null)
                .ToList();
            if (rootMenus.Count > 0)
            {
                foreach (var item in rootMenus)
                {
                    treeDtos.Add(GetChildMenus(item, permissionEntities));
                }
            }

            return await Result<IList<PermissionTreeResponseDto>>.SuccessAsync(treeDtos);
        }

        public async Task<Result<IList<PermissionInfoResponseDto>>> QueryPermissionsAsync(
            PermissionSearchRequestDto model)
        {
            var data = await _permissionRepository.ListAsync(new PermissionSpecification(model));
            return await Result<IList<PermissionInfoResponseDto>>.SuccessAsync(
                _mapper.Map<List<PermissionInfoResponseDto>>(data));
        }

        public async Task<Result<IList<PermissionTreeResponseDto>>> GetCurrentUserPermissions(int treeType)
        {
            var userId = _securityUser.GetUserId();

            if (userId != null)
            {
                var permissions = await _permissionRepository.QueryByUserAsync(userId.Value, treeType);

                IList<PermissionTreeResponseDto> treeDtos = new List<PermissionTreeResponseDto>();
                // 获取菜单目录
                var rootMenus = permissions.Where(i => i.ParentId == null)
                    .ToList();
                if (rootMenus.Count > 0)
                {
                    foreach (var item in rootMenus)
                    {
                        treeDtos.Add(GetChildMenus(item, permissions));
                    }
                }

                return await Result<IList<PermissionTreeResponseDto>>.SuccessAsync(treeDtos);
            }

            return new Result<IList<PermissionTreeResponseDto>>();
        }

        public async Task<Tuple<Stream, string>> ExportAsync()
        {
            var fileName = $"PermissionListExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";

            var permissionEntities =
                await _permissionRepository.ListAsync(new PermissionSpecification(new PermissionSearchRequestDto()));

            var list = new List<PermissionInfoResponseDto>();

            foreach (var item in permissionEntities)
            {
                var permissionInfoResponseDto = _mapper.Map<PermissionInfoResponseDto>(item);
                var firstOrDefault = permissionEntities.FirstOrDefault(i => i.Id == item.ParentId);
                if (firstOrDefault != null)
                {
                    permissionInfoResponseDto.ParentCode = firstOrDefault.Code;
                    permissionInfoResponseDto.ParentName = firstOrDefault.Name;
                }

                list.Add(permissionInfoResponseDto);
            }

            var stream = _excelProvider.WriteToStream(list, "Sheet1");

            return new Tuple<Stream, string>(stream, fileName);
        }

        public async Task<object?> ImportAsync(int importType, MemoryStream memoryStream)
        {
            try
            {
                var permissionTemplateResponseDtos =
                    _excelProvider.ReadToCollection<PermissionTemplateResponseDto>(memoryStream);

                if (permissionTemplateResponseDtos.Count == 0)
                {
                    return await Result.FailAsync("导入的数据不能为空");
                }

                IList<PermissionImportResponseDto> importDatas = new List<PermissionImportResponseDto>();

                // 校验数据
                foreach (var item in permissionTemplateResponseDtos)
                {
                    var permissionImportResponseDto = new PermissionImportResponseDto(item);
                    StringBuilder sb = new StringBuilder();


                    permissionImportResponseDto.ErrorMessage = sb.ToString();

                    importDatas.Add(permissionImportResponseDto);
                }

                var hasError = importDatas.Any(i => !string.IsNullOrEmpty(i.ErrorMessage));
                if (!hasError)
                {
                    var permissionEntities = _mapper.Map<IList<PermissionEntity>>(permissionTemplateResponseDtos);

                    await _permissionRepository.AddRangeAsync(permissionEntities);
                }

                return await Result<IList<PermissionImportResponseDto>>.SuccessAsync(importDatas);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        public Task<Tuple<Stream, string>> ExportTemplateAsync()
        {
            var fileName = $"PermissionTemplateExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";

            var stream = _excelProvider.WriteToStream<PermissionTemplateResponseDto>("Sheet1");

            return Task.FromResult(new Tuple<Stream, string>(stream, fileName));
        }

        private PermissionTreeResponseDto GetChildMenus(PermissionEntity parent, IList<PermissionEntity> menus)
        {
            var treeDto = new PermissionTreeResponseDto
            {
                Key = parent.Id,
                Code = parent.Code,
                Name = parent.Name,
                Icon = parent.Icon,
                Url = parent.Uri
            };

            var childCategories = menus.Where(i => i.ParentId == parent.Id)
                .ToList();
            if (childCategories.Count > 0)
            {
                treeDto.Children = new List<PermissionTreeResponseDto>();
                foreach (var child in childCategories)
                {
                    treeDto.Children.Add(GetChildMenus(child, menus));
                }
            }

            return treeDto;
        }
    }
}